import * as bluebird from 'bluebird';
import { Service } from 'egg';
import * as _ from 'lodash';

export default class ReportService extends Service {
  async aggregateInboundCount({ account, year }: { account?: string; year: number; }) {
    const { app, ctx } = this;
    const timeIntervals: any[] = [];
    for (let i = 1; i <= 12; i++) {
      timeIntervals.push({ MonthID: year + (i < 10 ? '0' + i : '' + i) });
    }
    const group = {
      _id: null,
      DealingCount: { $sum: '$DealingCount' },
      NotDealCount: { $sum: '$NotDealCount' },
      LeakCount: { $sum: '$LeakCount' },
      QueueLeakCount: { $sum: '$QueueLeakCount' },
      BlackListCount: { $sum: '$BlackListCount' },
      VoicemailCount: { $sum: '$VoicemailCount' },
      LimitCount: { $sum: '$LimitCount' },
    };
    const project = {
      InboundCount: {
        $add: [
          '$DealingCount',
          '$NotDealCount',
          '$LeakCount',
          '$QueueLeakCount',
          '$BlackListCount',
          '$VoicemailCount',
          '$LimitCount',
        ],
      },
    };
    const options = { cursor: { batchSize: 50000 }, allowDiskUse: true };
    ctx.logger.info('aggregate inbound count', year, account);
    const docs = await bluebird.map(timeIntervals, async (interval) => {
      const condition: any = { ...interval };
      if (account) {
        condition.AccountID = account;
      }
      const pipeline = [
        { $match: condition },
        { $group: group },
        { $project: project },
      ];
      const results = await app.reportDB.db().collection('cdr_report_service_call_in')
        .aggregate(pipeline, options).toArray();
      ctx.logger.info(interval, '-> complete,', results);
      return results[0];
    }, { concurrency: 30 });
    const result = { InboundCount: 0 };
    docs.reduce((_result, doc) => {
      if (doc && doc.InboundCount) {
        _result.InboundCount += doc.InboundCount;
      }
      return _result;
    }, result);
    ctx.logger.info('aggregate inbound count end', year, account);
    return result;
  }

  async aggregateOutbound({ account, year }: { account?: string; year: number; }) {
    const { app, ctx } = this;
    const timeIntervals: any[] = [];
    for (let i = 1; i <= 12; i++) {
      timeIntervals.push({ MonthID: year + (i < 10 ? '0' + i : '' + i) });
    }
    const group = {
      _id: null,
      DealingCount: { $sum: '$DealingCount' },
      NotDealCount: { $sum: '$NotDealCount' },
      LeakCount: { $sum: '$LeakCount' },
      OutboundTimeLength: { $sum: '$CallTimeLength' },
    };
    const project = {
      OutboundCount: { $add: ['$DealingCount', '$NotDealCount', '$LeakCount'] },
      OutboundTimeLength: 1,
    };
    const options = { cursor: { batchSize: 50000 }, allowDiskUse: true };
    ctx.logger.info('query outbound', year, account);
    const docs = await bluebird.map(timeIntervals, async (interval) => {
      const condition: any = { ...interval };
      if (account) {
        condition.AccountID = account;
      }
      const pipeline = [
        { $match: condition },
        { $group: group },
        { $project: project },
      ];
      const results = await app.reportDB.db().collection('cdr_report_call_out')
        .aggregate(pipeline, options).toArray();
      ctx.logger.info(interval, '-> complete,', results);
      return results[0];
    }, { concurrency: 30 });
    const result = { OutboundCount: 0, OutboundTimeLength: 0, OutboundTimeLengthHuman: '00:00:00' };
    docs.reduce((_result, doc) => {
      if (doc) {
        _result.OutboundCount += doc.OutboundCount;
        _result.OutboundTimeLength += doc.OutboundTimeLength;
      }
      return _result;
    }, result);
    ctx.logger.info('aggregate outbound end', year, account);
    result.OutboundTimeLengthHuman = this.convertSecondsToHHmmss(result.OutboundTimeLength);
    return result;
  }

  async aggregateInboundTimeLength({ account, year }: { account?: string; year: number; }) {
    const { app, ctx } = this;
    const timeIntervals: any[] = [];
    for (let i = 1; i <= 12; i++) {
      timeIntervals.push({ MonthID: year + (i < 10 ? '0' + i : '' + i) });
    }
    const group = {
      _id: null,
      CallInTimeLength: { $sum: '$CallInTimeLength' },
      NormalTransferTimeLength: { $sum: '$NormalTransferTimeLength' },
      DialTransferTimeLength: { $sum: '$DialTransferTimeLength' },
    };
    const project = {
      InboundTimeLength: {
        $subtract: [
          '$CallInTimeLength',
          { $add: ['$NormalTransferTimeLength', '$DialTransferTimeLength'] },
        ],
      },
    };
    const options = { cursor: { batchSize: 50000 }, allowDiskUse: true };
    ctx.logger.info('aggregate inbound time length', year, account);
    const docs = await bluebird.map(timeIntervals, async (interval) => {
      const condition: any = { ...interval };
      if (account) {
        condition.AccountID = account;
      }
      const pipeline = [
        { $match: condition },
        { $group: group },
        { $project: project },
      ];
      const results = await app.reportDB.db().collection('cdr_report_agent_houre')
        .aggregate(pipeline, options).toArray();
      ctx.logger.info(interval, '-> complete,', results);
      return results[0];
    }, { concurrency: 30 });
    const result = { InboundTimeLength: 0, InboundTimeLengthHuman: '00:00:00' };
    docs.reduce((_result, doc) => {
      if (doc) {
        _result.InboundTimeLength += doc.InboundTimeLength;
      }
      return _result;
    }, result);
    ctx.logger.info('aggregate inbound time length end', year, account);
    result.InboundTimeLengthHuman = this.convertSecondsToHHmmss(result.InboundTimeLength);
    return result;
  }

  public splitQueryTimeIntervals(beginTime: string, endTime: string, days: number) {
    const { app } = this;
    const SPLIT_SECONDS = 3600 * 24 * days;
    const timeEnd = endTime;
    let timeStart = beginTime;
    let timeInter = beginTime;
    const timeIntervals: any[] = [];
    while (
      app.m7Utils.DateTime.getDifferenceTime(timeEnd, timeStart) > SPLIT_SECONDS
    ) {
      timeInter = app.m7Utils.DateTime.getDateFormat(
        new Date(Date.parse(timeStart) + SPLIT_SECONDS * 1000),
      );
      timeIntervals.push({ $gte: timeStart, $lt: timeInter });
      timeStart = timeInter;
    }
    if (app.m7Utils.DateTime.getDifferenceTime(endTime, timeStart) > 0) {
      timeIntervals.push({ $gte: timeStart, $lt: timeEnd });
    }
    return timeIntervals;
  }

  private convertSecondsToHHmmss(sec: number | string) {
    if (typeof sec === 'string') {
      sec = parseInt(sec, 10);
    }
    const hh = (Math.floor(sec / 3600) + '').padStart(2, '0');
    const mm = (Math.floor((sec % 3600) / 60) + '').padStart(2, '0');
    const ss = (sec % 3600 % 60 + '').padStart(2, '0');
    return `${hh}:${mm}:${ss}`;
  }
}
